home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-10-25 | 27.3 KB | 1,382 lines | [TEXT/CWIE] |
- /*********************************************************************
- Project : GUSI - Grand Unified Socket Interface
- File : GUSIFile.cp - Implementation of file calls
- Author : Matthias Neeracher <neeri@iis.ethz.ch>
- Language : MPW C
-
- $Log: GUSIFile.cp,v $
- Revision 1.4 1994/12/30 19:56:13 neeri
- New dispatching mechanism for file names.
- Add chmod().
-
- Revision 1.3 1994/08/10 00:29:25 neeri
- Sanitized for universal headers.
-
- Revision 1.2 1994/05/01 23:37:55 neeri
- Added utime().
- Fixed stat() permissions for locked files.
-
- Revision 1.1 1994/03/08 23:51:24 neeri
- Initial revision
-
- Revision 0.34 1993/09/11 00:00:00 neeri
- Trying to avoid stream.h unless absolutely necessary
-
- Revision 0.33 1993/08/25 00:00:00 neeri
- Need 2 include TextUtils since E.T.O. #12
-
- Revision 0.32 1993/07/17 00:00:00 neeri
- Adapt to BSD 4.3, scandir
-
- Revision 0.31 1993/06/27 00:00:00 neeri
- f?truncate
-
- Revision 0.30 1993/02/23 00:00:00 neeri
- fgetfileinfo
-
- Revision 0.29 1993/02/01 00:00:00 neeri
- Made nlink for directories return something meaningful
-
- Revision 0.28 1993/01/15 00:00:00 neeri
- rename() has to be more careful about renaming order
-
- Revision 0.27 1993/01/15 00:00:00 neeri
- choose() should *not* count the string terminator.
-
- Revision 0.26 1993/01/03 00:00:00 neeri
- Respect configuration
-
- Revision 0.25 1993/01/01 00:00:00 neeri
- fsetfileinfo
-
- Revision 0.24 1992/12/20 00:00:00 neeri
- do_putfile now respects default
-
- Revision 0.23 1992/12/13 00:00:00 neeri
- stat now returns DirID/FileNo, not parID for the ino field
-
- Revision 0.22 1992/12/08 00:00:00 neeri
- getcwd()
-
- Revision 0.21 1992/11/28 00:00:00 neeri
- TEXT files are now considered executable
-
- Revision 0.20 1992/11/15 00:00:00 neeri
- Rename GUSIFSp_P.h to TFileSpec.h (there we go again)
-
- Revision 0.19 1992/10/28 00:00:00 neeri
- Forgot to change to dirent
-
- Revision 0.18 1992/09/15 00:00:00 neeri
- Slight error in do_stat()
-
- Revision 0.17 1992/09/12 00:00:00 neeri
- Rename Paths.h to GUSIFSp_P.h
-
- Revision 0.16 1992/09/08 00:00:00 neeri
- readlink()
-
- Revision 0.15 1992/09/06 00:00:00 neeri
- Adapt alias resolution to new libraries
-
- Revision 0.14 1992/07/13 00:00:00 neeri
- CopyIconFamily
-
- Revision 0.13 1992/06/27 00:00:00 neeri
- choose()
-
- Revision 0.12 1992/06/26 00:00:00 neeri
- symlink is starting to work
-
- Revision 0.11 1992/06/21 00:00:00 neeri
- symlink()
-
- Revision 0.10 1992/06/15 00:00:00 neeri
- Separated path stuff
-
- Revision 0.9 1992/05/21 00:00:00 neeri
- Implemented select()
-
- Revision 0.8 1992/04/20 00:00:00 neeri
- C++ rewrite
-
- Revision 0.7 1992/04/05 00:00:00 neeri
- lseek
-
- Revision 0.6 1992/03/22 00:00:00 neeri
- Adapted for GUSI, change chdir stuff
-
- Revision 0.5 1992/02/11 00:00:00 neeri
- Incorporated bug fix by John Reekie
-
- Revision 0.4 1991/12/12 00:00:00 neeri
- FSp2RelPath
-
- Revision 0.3 1991/12/09 00:00:00 neeri
- Radical overhaul
-
- Revision 0.2 1991/05/28 00:00:00 neeri
- isatty()
-
- Revision 0.1 1991/05/28 00:00:00 neeri
- Created
-
- *********************************************************************/
-
- #include "GUSIFile_P.h"
- #include "TFileSpec.h"
-
- #include <Errors.h>
- #include <Resources.h>
- #include <Script.h>
- #include <Finder.h>
- #include <Folders.h>
- #include <Devices.h>
- #include <Memory.h>
- #include <Aliases.h>
- #include <string.h>
- #include <PLStringFuncs.h>
- #include <errno.h>
- #ifdef GUSI_FILE_DEBUG
- #include <stream.h>
- #endif
- #include <StdLib.h>
- #include <Time.h>
- #include <TextUtils.h>
- #include <unistd.h>
- #include <utime.h>
-
- #pragma segment GUSI
-
- FileSocketDomain * FileSockets;
-
- /********************* FileSocketDomain members *********************/
-
- #ifndef GUSI_DISPATCH
- Boolean IsDevice(const char * fn)
- {
- return (
- (fn[0] | 0x20) == 'd'
- && (fn[1] | 0x20) == 'e'
- && (fn[2] | 0x20) == 'v'
- && fn[3] == ':');
- }
-
- int File_error(OSErr err)
- {
- switch (err) {
- case noErr:
- errno = 0;
-
- return 0;
- case bdNamErr:
- return GUSI_error(ENAMETOOLONG);
- case afpObjectTypeErr:
- return GUSI_error(ENOTDIR);
- case fnfErr:
- case dirNFErr:
- return GUSI_error(ENOENT);
- case dupFNErr:
- return GUSI_error(EEXIST);
- case dirFulErr:
- case dskFulErr:
- return GUSI_error(ENOSPC);
- case fBsyErr:
- return GUSI_error(EBUSY);
- case tmfoErr:
- return GUSI_error(ENFILE);
- case fLckdErr:
- case permErr:
- case afpAccessDenied:
- return GUSI_error(EACCES);
- case wPrErr:
- case vLckdErr:
- return GUSI_error(EROFS);
- case badMovErr:
- return GUSI_error(EINVAL);
- case diffVolErr:
- return GUSI_error(EXDEV);
- default:
- return GUSI_error(EINVAL);
- }
- }
-
- Socket * FileSocketDomain::open(const GUSIFileRef & ref, int oflag)
- {
- Socket * sock;
-
- if (ref.IsDevice())
- if (MPWDomain::open)
- return (Socket *) MPWDomain::open(ref.name, oflag);
- else
- return (Socket *) GUSI_error_nil(EINVAL);
- else {
- Boolean fresh;
-
- if (ref.Error()) {
- File_error(ref.Error());
-
- return nil;
- }
-
- fresh = (oflag & O_CREAT) && !ref.spec->Exists();
-
- if (MPWDomain::open)
- sock = (Socket *) MPWDomain::open(ref.spec->RelPath(), oflag);
- else
- sock = (Socket *) MacFileSocket::open(*ref.spec, oflag);
-
- if (sock && fresh)
- GUSIConfig.SetDefaultFType(*ref.spec);
- }
-
- return sock;
- }
-
- #define SFSaveDisk (* (short *) 0x0214)
- #define CurDirStore (* (long *) 0x0398)
-
- static long currentDir;
- static SFReply reply;
- static char * customPrompt;
-
- static int do_getfile(
- TFileSpec * defaultFile,
- TFileSpec * result,
- short numTypes,
- SFTypeList types)
- {
- Point myPoint = {75, 75};
-
- if (defaultFile) {
- *defaultFile += (StringPtr) "\p";
-
- SFSaveDisk = -defaultFile->vRefNum;
- CurDirStore = defaultFile->parID;
- }
-
- SFGetFile(myPoint, (StringPtr) "\p", NULL, numTypes, types, NULL, &reply);
-
- if (reply.good)
- *result = TFileSpec(reply.vRefNum, reply.fName);
-
- return reply.good;
- }
-
- static pascal Boolean FolderFFilter(ParmBlkPtr p)
- {
- return !(p->fileParam.ioFlAttrib & ioDirMask);
- }
-
- #if GENERATINGCFM
- RoutineDescriptor uFolderFFilter =
- BUILD_ROUTINE_DESCRIPTOR(uppFileFilterProcInfo, FolderFFilter);
- #else
- #define uFolderFFilter FolderFFilter
- #endif
-
- static ControlHandle GetDlgCtrl(DialogPtr dlg, short item)
- {
- short kind;
- Handle hdl;
- Rect box;
-
- GetDItem(dlg, item, &kind, &hdl, &box);
- return (ControlHandle) hdl;
- }
-
- static pascal short GetDirDlgHook(short item, DialogPtr dlgPtr)
- {
- switch (item) {
- case sfHookFirstCall:
- if (customPrompt)
- setitext(Handle(GetDlgCtrl(dlgPtr, 13)), customPrompt);
- break;
- case 11:
- if (reply.fType) {
- if (!reply.fName[0])
- currentDir = reply.fType;
- else {
- TFileSpec dir(reply.vRefNum, CurDirStore, reply.fName);
-
- dir += (StringPtr) "\p";
-
- currentDir = dir.parID;
- }
-
- return 1;
- }
- break;
-
- case 12:
- currentDir = CurDirStore;
-
- return 1;
- case sfHookNullEvent:
- if (!reply.fType)
- HiliteControl(GetDlgCtrl(dlgPtr, 11), 255);
- else
- HiliteControl(GetDlgCtrl(dlgPtr, 11), 0);
- break;
- }
-
- return item;
- }
-
- #if GENERATINGCFM
- RoutineDescriptor uGetDirDlgHook =
- BUILD_ROUTINE_DESCRIPTOR(uppDlgHookProcInfo, GetDirDlgHook);
- #else
- #define uGetDirDlgHook GetDirDlgHook
- #endif
-
- static int do_getfolder(
- char * prompt,
- TFileSpec * defaultFile,
- TFileSpec * result)
- {
- Point myPoint = {75, 75};
-
- if (defaultFile) {
- *defaultFile += (StringPtr) "\p";
-
- SFSaveDisk = -defaultFile->vRefNum;
- CurDirStore = defaultFile->parID;
- }
-
- customPrompt = prompt && *prompt ? prompt : nil;
-
- SFPGetFile(
- myPoint,
- (StringPtr) "\p",
- FileFilterUPP(&uFolderFFilter),
- -1,
- nil,
- DlgHookUPP(&uGetDirDlgHook),
- &reply,
- GUSIRsrcID,
- nil);
-
- if (reply.good) {
- result->vRefNum = -SFSaveDisk;
- result->parID = currentDir;
- --*result;
- }
-
- return reply.good;
- }
-
- static int do_putfile(
- char * prompt,
- TFileSpec * defaultFile,
- TFileSpec * result)
- {
- Point myPoint = {75, 75};
- StringPtr defName;
- Str255 prmpt;
-
- CopyC2PStr(prompt, prmpt);
-
- if (defaultFile) {
- SFSaveDisk = -defaultFile->vRefNum;
- CurDirStore = defaultFile->parID;
- defName = defaultFile->name;
- } else
- defName = (StringPtr) "\p";
-
- SFPutFile(myPoint, prmpt, defName, NULL, &reply);
-
- if (reply.good)
- *result = TFileSpec(reply.vRefNum, reply.fName);
-
- return reply.good;
- }
-
- int FileSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
- {
- sa_constr_file * constr = (sa_constr_file *) constraint;
- TFileSpec file;
- TFileSpec df;
- TFileSpec * defaultFile;
- Boolean good;
- char * path;
- int len;
-
- if (flags & CHOOSE_DEFAULT) {
- df = TFileSpec((char *) name);
- defaultFile = df.Error() ? nil : &df;
- } else
- defaultFile = nil;
-
- if (flags & CHOOSE_NEW)
- good = do_putfile(prompt, defaultFile, &file);
- else if (flags & CHOOSE_DIR)
- good = do_getfolder(prompt, defaultFile, &file);
- else if (constr)
- good = do_getfile(defaultFile, &file, constr->numTypes, constr->types);
- else
- good = do_getfile(defaultFile, &file, -1, nil);
-
- if (good) {
- path = file.FullPath();
- len = int(strlen(path));
-
- if (len < *namelen)
- memcpy(name, path, (*namelen = len)+1);
- else
- return GUSI_error(EINVAL);
- } else
- return GUSI_error(EINTR);
-
- return 0;
- }
-
- int FileSocketDomain::remove(const GUSIFileRef & ref)
- {
- OSErr err;
-
- if (ref.IsDevice())
- return GUSI_error(EINVAL);
- if (ref.Error())
- return File_error(ref.Error());
-
- switch (err = HDelete(ref.spec->vRefNum, ref.spec->parID, ref.spec->name)) {
- case noErr:
- return 0;
- case fBsyErr: {
- const CInfoPBRec * info = ref.Info();
-
- if (info && !IsFile(*info) && info->dirInfo.ioDrNmFls)
- return GUSI_error(ENOTEMPTY);
- else
- return GUSI_error(EBUSY);
- }
- default:
- return File_error(err);
- }
- }
-
- int FileSocketDomain::rename(const GUSIFileRef & ref, const char *newname)
- {
- OSErr err;
-
- if (ref.IsDevice())
- return GUSI_error(EINVAL);
- if (ref.Error())
- return File_error(ref.Error());
- if (IsDevice(newname))
- return GUSI_error(EINVAL);
-
- TFileSpec newnm(newname, true);
-
- switch (err = FSpSmartMove((TFileSpec *)ref.spec, &newnm)) {
- case fBsyErr:
- return GUSI_error(ENOTEMPTY);
- default:
- return File_error(err);
- }
-
- return 0;
- }
-
- void FileSocketDomain::fsetfileinfo(const GUSIFileRef & ref, unsigned long newcreator, unsigned long newtype)
- {
- if (ref.IsDevice()) {
- GUSI_error(EINVAL);
-
- return;
- }
-
- FInfo info;
-
- if (ref.Error() || !ref.spec->Exists()
- || HGetFInfo(ref.spec->vRefNum, ref.spec->parID, ref.spec->name, &info)
- ) {
- GUSI_error(EIO);
-
- return;
- }
-
- info.fdType = newtype;
- info.fdCreator = newcreator;
-
- if (HSetFInfo(ref.spec->vRefNum, ref.spec->parID, ref.spec->name, &info))
- GUSI_error(EIO);
-
- errno = 0;
- }
-
- void FileSocketDomain::fgetfileinfo(const GUSIFileRef & ref, unsigned long * creator, unsigned long * type)
- {
- if (ref.IsDevice()) {
- GUSI_error(EINVAL);
-
- return;
- }
-
- FInfo info;
-
- if (ref.Error() || !ref.spec->Exists()
- || HGetFInfo(ref.spec->vRefNum, ref.spec->parID, ref.spec->name, &info)
- ) {
- GUSI_error(EIO);
-
- return;
- }
-
- if (creator)
- *creator = info.fdCreator;
-
- if (type)
- *type = info.fdType;
-
- errno = 0;
- }
-
- int FileSocketDomain::faccess(const GUSIFileRef & ref, unsigned int cmd, long* arg)
- {
- return GUSI_error(EINVAL);
- }
-
- static OSErr GetVolume(const CInfoPBRec & cb, ParamBlockRec & pb)
- {
- Str63 name;
-
- pb.volumeParam.ioNamePtr = name;
- pb.volumeParam.ioVRefNum = cb.hFileInfo.ioVRefNum;
- pb.volumeParam.ioVolIndex = 0;
-
- return PBGetVInfo(&pb, false);
- }
-
- static int do_stat(const GUSIFileRef & ref, struct stat & buf)
- {
- if (!ref.Info())
- return GUSI_error(ENOENT);
-
- const CInfoPBRec & cb = *ref.Info();
- ParamBlockRec pb;
-
- if (GetVolume(cb, pb))
- return GUSI_error(ENOENT);
-
- buf.st_dev = pb.ioParam.ioVRefNum;
- buf.st_ino = cb.dirInfo.ioDrDirID;
- buf.st_nlink = 1;
- buf.st_uid = 0;
- buf.st_gid = 0;
- buf.st_rdev = 0;
- buf.st_atime = cb.hFileInfo.ioFlMdDat;
- buf.st_mtime = cb.hFileInfo.ioFlMdDat;
- buf.st_ctime = cb.hFileInfo.ioFlCrDat;
- buf.st_blksize = pb.volumeParam.ioVAlBlkSiz;
-
- if (!IsFile(cb)) {
- TFileSpec spec;
- CInfoPBRec info;
-
- spec.vRefNum = pb.ioParam.ioVRefNum;
- spec.parID = cb.dirInfo.ioDrDirID;
-
- ++buf.st_nlink;
-
- if (GUSIConfig.accurStat) {
- for (int i = 0; i++ < cb.dirInfo.ioDrNmFls;) {
- spec = spec[i];
- if (!spec.Error() && !spec.CatInfo(info) && !IsFile(info))
- ++buf.st_nlink;
- }
- } else {
- buf.st_nlink += cb.dirInfo.ioDrNmFls;
- }
-
- buf.st_mode = S_IFDIR | 0666;
-
- if (GUSIExec(ref))
- buf.st_mode |= 0111;
-
- buf.st_size = cb.dirInfo.ioDrNmFls;
- } else if (IsAlias(cb)) {
- buf.st_mode = S_IFLNK | 0777;
- buf.st_size = cb.hFileInfo.ioFlRLgLen; /* Data fork is ignored */
- } else if (cb.hFileInfo.ioFlFndrInfo.fdType == '∑OCK') {
- buf.st_mode = S_IFSOCK | 0666;
- buf.st_size = cb.hFileInfo.ioFlRLgLen; /* Data fork is ignored */
- } else {
- buf.st_mode = S_IFREG | 0666;
-
- if (cb.hFileInfo.ioFlAttrib & 0x01)
- buf.st_mode &= ~0222;
-
- if (GUSIExec(ref))
- buf.st_mode |= 0111;
-
- buf.st_size = cb.hFileInfo.ioFlLgLen; /* Resource fork is ignored */
- }
-
- buf.st_blocks = (buf.st_size + buf.st_blksize - 1) / buf.st_blksize;
-
- return 0;
- }
-
- static int do_special_stat(const GUSIFileRef & ref, struct stat & buf)
- {
- buf.st_dev = 0;
- buf.st_ino = 0;
- buf.st_mode = S_IFCHR | 0666 ;
- buf.st_nlink = 1;
- buf.st_uid = 0;
- buf.st_gid = 0;
- buf.st_rdev = 0;
- buf.st_size = 1;
- buf.st_atime = time(NULL);
- buf.st_mtime = time(NULL);
- buf.st_ctime = time(NULL);
- buf.st_blksize = 1;
- buf.st_blocks = 1;
-
- if (GUSIExec(ref))
- buf.st_mode |= 0111;
-
- return 0;
- }
-
- int FileSocketDomain::stat(const GUSIFileRef & ref, struct stat * buf)
- {
- if (ref.IsDevice())
- return do_special_stat(ref, *buf);
- else if (ref.Error())
- return GUSI_error(ENOENT);
- else
- return do_stat(ref, *buf);
- }
-
- int FileSocketDomain::chmod(const GUSIFileRef & ref, mode_t mode)
- {
- const CInfoPBRec * cb;
-
- if (ref.IsDevice())
- return GUSI_error(EINVAL);
-
- if (ref.Error() || !(cb = ref.Info()))
- return GUSI_error(ENOENT);
-
- if (!(cb->dirInfo.ioFlAttrib & 0x10))
- if (mode & S_IWUSR) {
- if (cb->hFileInfo.ioFlAttrib & 0x01)
- HRstFLock(ref.spec->vRefNum, ref.spec->parID, ref.spec->name);
- } else {
- if (!(cb->hFileInfo.ioFlAttrib & 0x01))
- HSetFLock(ref.spec->vRefNum, ref.spec->parID, ref.spec->name);
- }
-
- return 0;
- }
-
- int FileSocketDomain::utime(const GUSIFileRef & ref, const struct utimbuf * times)
- {
- if (ref.IsDevice())
- return GUSI_error(EINVAL);
-
- CInfoPBRec cb;
- const CInfoPBRec * cbp;
-
- if (ref.Error() || !(cbp = ref.Info()))
- return GUSI_error(ENOENT);
-
- cb = *cbp;
- cb.hFileInfo.ioVRefNum = ref.spec->vRefNum;
- cb.hFileInfo.ioDirID = ref.spec->parID;
- cb.hFileInfo.ioNamePtr = ref.spec->name;
- cb.hFileInfo.ioFlMdDat = times ? times->modtime : time(nil);
- // times->actime is ignored. The Mac has no access times.
-
- return File_error(PBSetCatInfoSync(&cb));
- }
-
- int FileSocketDomain::access(const GUSIFileRef & ref, int mode)
- {
- if (ref.IsDevice())
- return GUSI_error(EINVAL);
-
- const CInfoPBRec * info = ref.Info();
-
- if (!info)
- switch (ref.Error()) {
- case afpAccessDenied:
- return GUSI_error(EACCES);
- case ioErr:
- return GUSI_error(EIO);
- case bdNamErr:
- case fnfErr:
- case nsvErr:
- case paramErr:
- case dirNFErr:
- case afpObjectTypeErr:
- /* ENOENT */
- default:
- return GUSI_error(ENOENT); /* Don't know what the error is. */
- }
-
- //
- // Under our simplifying assumptions, we don't check AppleShare permissions,
- // so if we managed to do a GetCatInfo, R_OK and F_OK are already assumed
- // to be true
- //
- if (mode & W_OK) {
- //
- // Check if volume is locked
- //
- HParamBlockRec vol;
-
- vol.volumeParam.ioNamePtr = nil;
- vol.volumeParam.ioVolIndex = 0;
- vol.volumeParam.ioVRefNum = ref.spec->vRefNum;
-
- if (PBHGetVInfoSync(&vol))
- return GUSI_error(EINVAL); // Should never happen
-
- if (vol.volumeParam.ioVAtrb & 0x8080)
- return GUSI_error(EROFS); // Yup, volume is locked
-
- //
- // Check if file is locked
- //
- if (IsFile(*info) && info->hFileInfo.ioFlAttrib & 0x01)
- return GUSI_error(EACCES); // Yup, file is locked
- }
-
- //
- // Check executability via Exec hook
- //
- if (mode & X_OK)
- if (!GUSIExec(ref))
- return GUSI_error(EACCES);
-
- return 0;
- }
-
- Boolean GUSIDefaultExec(const GUSIFileRef & ref)
- {
- const CInfoPBRec * info = ref.Info();
-
- if (info)
- if (IsFile(*info))
- switch (info->hFileInfo.ioFlFndrInfo.fdType) {
- case 'APPL':
- case 'appe':
- return true;
- }
- else
- return true; // All directories are considered searchable
-
- return false;
- }
-
- /************************ FileSocket members ************************/
-
- int FileSocket::fcntl(unsigned int, int)
- {
- return GUSI_error(EOPNOTSUPP);
- }
-
- int FileSocket::ioctl(unsigned int, void *)
- {
- return GUSI_error(EOPNOTSUPP);
- }
-
- int FileSocket::fstat(struct stat * buf)
- {
- GUSIFileRef ref(fRefNum, FileSocketDomain::willStat);
-
- if (ref.Error())
- return GUSI_error(ENOENT);
- else
- return do_stat(ref, *buf);
- }
-
- int FileSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
- {
- int goodies = 0;
-
- // Simplicistic implementation
-
- if (canRead) {
- *canRead = true;
- ++goodies;
- }
-
- if (canWrite) {
- *canWrite = true;
- ++goodies;
- }
-
- return goodies;
- }
-
- FileSocket::~FileSocket()
- {
- }
-
- /***************** Things that happen to real files only *****************/
-
- OSErr VRef2Icon(short vRef, Handle * icon)
- {
- OSErr err;
- HParmBlkPtr hpp;
- ParmBlkPtr pp;
- HParamBlockRec hpb;
-
- hpp = &hpb;
- pp = (ParmBlkPtr) hpp;
- hpp->volumeParam.ioVRefNum = vRef;
- hpp->volumeParam.ioNamePtr = nil;
- hpp->volumeParam.ioVolIndex= 0;
- if (err = PBHGetVInfoSync(hpp))
- return err;
-
- pp->cntrlParam.ioVRefNum = hpb.volumeParam.ioVDrvInfo;
- pp->cntrlParam.ioCRefNum = hpb.volumeParam.ioVDRefNum;
- pp->cntrlParam.csCode = 21;
-
- if (err = PBControlSync(pp))
- return err;
-
- PtrToHand(*(Ptr *) pp->cntrlParam.csParam, icon, 256);
-
- return noErr;
- }
-
- typedef OSType TTypeMap[2];
-
- static TTypeMap map[] = {
- {'amnu', 'faam'},
- {'ctrl', 'fact'},
- {'extn', 'faex'},
- {'pref', 'fapf'},
- {'prnt', 'fapn'},
- {'empt', 'trsh'},
- {'trsh', 'trsh'},
- {'strt', 'fast'},
- {'macs', 'fasy'},
- { 0, 0}
- };
-
- #ifdef GUSI_FILE_DEBUG
- ostream & operator<<(ostream & str, OSType * ty)
- {
- return str << "'"
- << char((*ty >> 24) & 0xFF)
- << char((*ty >> 16) & 0xFF)
- << char((*ty >> 8) & 0xFF)
- << char(*ty & 0xFF)
- << "'";
- }
- #endif
-
- void OurResidentAliasExpert(
- TFileSpec & file,
- OSType * fCreator,
- OSType * fType,
- TFileSpec * iconFile,
- short * iconID)
- {
- Boolean appleShare;
- CInfoPBRec info;
- GetVolParmsInfoBuffer volParms;
- HParamBlockRec pb;
-
- *fCreator = 'MACS';
- *iconFile = file;
- *iconID = kCustomIconResource;
-
- if (file.parID == fsRtParID)
- appleShare = true;
- else {
- if (file.CatInfo(info))
- goto error;
-
- appleShare = !IsFile(info);
- }
-
- if (appleShare) {
- pb.ioParam.ioNamePtr = nil;
- pb.ioParam.ioVRefNum = file.vRefNum;
- pb.ioParam.ioBuffer = Ptr(&volParms);
- pb.ioParam.ioReqCount= sizeof(GetVolParmsInfoBuffer);
-
- if (PBHGetVolParmsSync(&pb) || !volParms.vMServerAdr)
- appleShare = false;
- }
-
- if (appleShare)
- if (file.parID == fsRtParID)
- *fType = 'srvr';
- else if (!HasRdPerm(info))
- *fType = 'fadr';
- else
- *fType = 'faet';
- else if (file.parID == fsRtParID)
- *fType = 'hdsk';
- else if (!IsFile(info))
- if (DirIsMounted(info))
- *fType = 'famn';
- else if (DirIsExported(info))
- *fType = 'fash';
- else if (DirIsShared(info))
- *fType = 'faet';
- else
- *fType = 'fdrp';
-
- if (file.parID == fsRtParID) {
- iconFile->parID = fsRtDirID;
- PLstrcpy(iconFile->name, (StringPtr) "\pIcon\n");
- } else if (!IsFile(info)) {
- if (info.dirInfo.ioDrDirID < 9) {
- short vRef;
- long dirID;
-
- for (TTypeMap * mapp = map; **mapp; ++mapp)
- if (!FindFolder(file.vRefNum, (*mapp)[0], false, &vRef, &dirID))
- if (dirID == info.dirInfo.ioDrDirID) {
- *fType = (*mapp)[1];
-
- break;
- }
- }
- *iconFile += (StringPtr) "\pIcon\n";
- } else {
- *fType = info.hFileInfo.ioFlFndrInfo.fdType;
- *fCreator= info.hFileInfo.ioFlFndrInfo.fdCreator;
- }
-
- #ifdef GUSI_FILE_DEBUG
- cerr << "Type = " << fType << ", creator = " << fCreator << endl;
- cerr << "Look for custom icons in " << iconFile->FullPath() << endl;
- #endif
-
- return;
- error:
- *fType = 0;
- *fCreator = 0;
- }
-
- static OSType iconTypes[] = {
- 'ICN#',
- 'ics#',
- 'icl4',
- 'ics4',
- 'icl8',
- 'ics8',
- 0
- };
-
- Boolean CopyIconFamily(short srcResFile, short srcID, short dstResFile, short dstID)
- {
- Handle icon;
- Boolean success = false;
- OSType * types;
-
- for (types = iconTypes; *types; ++types) {
- UseResFile(srcResFile);
- if (icon = Get1Resource(*types, srcID)) {
- UseResFile(dstResFile);
- DetachResource(icon);
- AddResource(icon, *types, dstID, (StringPtr) "\p");
-
- success = success || !ResError();
- }
- }
-
- return success;
- }
-
- Boolean AddIconsToFile(
- const TFileSpec & origFile,
- short aliasFile,
- OSType fCreator,
- OSType fType,
- const FSSpec & iconFile,
- short iconID)
- {
- short iFile;
- Boolean success;
- Handle icon;
-
- iFile = FSpOpenResFile(&iconFile, fsRdPerm);
-
- if (iFile == -1)
- goto noCustom;
-
- success = CopyIconFamily(iFile, iconID, aliasFile, kCustomIconResource);
-
- CloseResFile(iFile);
-
- if (success)
- return true;
-
- #ifdef GUSI_FILE_DEBUG
- cerr << "No custom Icons found." << endl;
- #endif
-
- noCustom:
- if (fType == 'hdsk' && fCreator == 'MACS')
- if (!VRef2Icon(origFile.vRefNum, &icon)) {
- #ifdef GUSI_FILE_DEBUG
- cerr << "Found icon for disk drive." << endl;
- #endif
- AddResource(icon, 'ICN#', kCustomIconResource, (StringPtr) "\p");
-
- return !ResError();
- }
-
- return false;
- }
-
- int symlink(const char* linkto, const char* linkname)
- {
- if (IsDevice(linkto))
- return GUSI_error(EINVAL);
- if (IsDevice(linkname))
- return GUSI_error(EINVAL);
-
- OSType fType;
- OSType fCreator;
- short iconID;
- short aliasFile;
- AliasHandle alias;
- Boolean customIcon;
- TFileSpec iconFile;
- FInfo info;
-
- if (!hasAlias || !hasMakeFSSpec)
- return GUSI_error(EOPNOTSUPP);
-
- TFileSpec oldnm(linkto);
-
- if (oldnm.Error() || !oldnm.Exists())
- return GUSI_error(EIO);
-
- TFileSpec newnm(linkname, true);
-
- if (newnm.Error())
- return GUSI_error(EIO);
-
- if (newnm.Exists())
- return GUSI_error(EEXIST);
-
- OurResidentAliasExpert(oldnm, &fCreator, &fType, &iconFile, &iconID);
-
- #ifdef GUSI_FILE_DEBUG
- cerr << "Creating " << newnm.FullPath() << endl;
- #endif
-
- FSpCreateResFile(&newnm, fCreator, fType, smSystemScript);
-
- if (ResError())
- return GUSI_error(EIO);
-
- #ifdef GUSI_FILE_DEBUG
- cerr << "Opening " << newnm.FullPath() << endl;
- #endif
-
- aliasFile = FSpOpenResFile(&newnm, fsRdWrPerm);
-
- if (aliasFile == -1)
- goto deleteFile;
-
- #ifdef GUSI_FILE_DEBUG
- cerr << "Creating alias for " << oldnm.FullPath() << " in " << newnm.FullPath() << endl;
- #endif
-
- if (NewAlias(nil, &oldnm, &alias))
- goto closeFile;
-
- #ifdef GUSI_FILE_DEBUG
- cerr << "Adding alias to file." << endl;
- #endif
-
- AddResource((Handle) alias, 'alis', 0, oldnm.name);
-
- if (ResError())
- goto deleteAlias;
-
- customIcon = AddIconsToFile(oldnm, aliasFile, fCreator, fType, iconFile, iconID);
-
- #ifdef GUSI_FILE_DEBUG
- cerr << "There were " << (customIcon ? "" : "no ") << "custom Icons." << endl;
- #endif
-
- CloseResFile(aliasFile);
-
- FSpGetFInfo(&newnm, &info);
- info.fdFlags |= (1 << 15) | (customIcon ? (1 << 10) : 0);
- info.fdFlags &= ~(1 << 8);
- FSpSetFInfo(&newnm, &info);
-
- return 0;
-
- deleteAlias:
- DisposHandle((Handle) alias);
- closeFile:
- CloseResFile(aliasFile);
- deleteFile:
- FSpDelete(&newnm);
-
- return GUSI_error(EIO);
- }
-
- int readlink(const char * path, char * buf, int bufsiz)
- {
- if (IsDevice(path))
- return GUSI_error(EINVAL);
-
- char * resPath;
- int len;
- TFileSpec file(path, true);
-
- if (!(resPath = file.FullAliasPath()))
- if (file.Error() == resFNotFound)
- return GUSI_error(EINVAL);
- else
- return File_error(file.Error());
-
- len = strlen(resPath);
- strncpy(buf, resPath, bufsiz);
-
- if (len >= bufsiz)
- return GUSI_error(ENAMETOOLONG);
- else
- return len;
- }
-
- #endif
-
- /************************* directory stuff **************************/
-
- struct dir {
- short index;
- short vol;
- long dirID;
- dirent entry;
- };
-
- DIR * opendir(const char * name)
- {
- DIR * d;
- TFileSpec spec(name);
-
- if (spec.Error())
- goto error;
-
- spec += (StringPtr) "\p";
-
- if (spec.Error())
- goto error;
-
- d = (DIR *) NewPtr(sizeof(DIR));
-
- d->index = 1;
- d->vol = spec.vRefNum;
- d->dirID = spec.parID;
-
- return d;
-
- error:
- File_error(spec.Error());
-
- return nil;
- }
-
- struct dirent * readdir(DIR * dirp)
- {
- TFileSpec spec;
- int i;
- int e = errno;
-
- spec.vRefNum = dirp->vol;
- spec.parID = dirp->dirID;
- spec.name[0] = 0;
-
- spec = spec[dirp->index++];
-
- if (spec.Error())
- goto error;
-
- dirp->entry.d_fileno = spec.LastInfo()->dirInfo.ioDrDirID;
- dirp->entry.d_namlen = *spec.name;
-
- memcpy(dirp->entry.d_name, (char *) spec.name+1, dirp->entry.d_namlen);
-
- dirp->entry.d_name[dirp->entry.d_namlen] = 0;
-
- i = dirp->entry.d_namlen;
- do
- dirp->entry.d_name[i++] = 0;
- while (i & 3);
-
- dirp->entry.d_reclen = sizeof(u_long)+sizeof(u_short)+sizeof(u_short)+i;
-
- return &dirp->entry;
-
- error:
- File_error(spec.Error());
-
- if (errno == ENOENT)
- errno = e;
-
- return nil;
- }
-
- long telldir(const DIR * dirp)
- {
- return dirp->index;
- }
-
- void seekdir(DIR * dirp, long loc)
- {
- dirp->index = (short) loc;
- }
-
- void rewinddir(DIR * dirp)
- {
- dirp->index = 1;
- }
-
- int closedir(DIR * dirp)
- {
- DisposPtr((Ptr) dirp);
-
- return 0;
- }
-
- int scandir(
- const char * name,
- struct dirent *** namelist,
- int (*want)(struct dirent *),
- int (*cmp)(const void *, const void *))
- {
- struct dirent * entry;
- struct dirent * copy;
- struct dirent ** names;
- int count;
- DIR * dirp;
- CInfoPBRec info;
- TFileSpec spec;
-
- if ((dirp = opendir(name)) == NULL)
- return -1;
-
- spec.vRefNum = dirp->vol;
- spec.parID = dirp->dirID;
- --spec;
-
- if (spec.CatInfo(info))
- return File_error(spec.Error());
-
- names = (struct dirent **) malloc(info.dirInfo.ioDrNmFls * sizeof(struct dirent *));
- if (names == NULL)
- return GUSI_error(ENOMEM);
-
- count = 0;
- while ((entry = readdir(dirp)) != NULL) {
- if (want && !(*want)(entry))
- continue; /* Don't want this entry */
-
- if (!(copy = (struct dirent *)malloc(entry->d_reclen))) {
- free(names);
-
- return GUSI_error(ENOMEM);
- }
-
- memcpy(copy, entry, entry->d_reclen);
-
- names[count++] = copy;
- }
-
- closedir(dirp);
-
- if (count && cmp)
- qsort(names, count, sizeof(struct dirent *), cmp);
-
- *namelist = names;
-
- return count;
- }
-
- int chdir(const char * path)
- {
- TFileSpec dir(path);
-
- if (dir.Error())
- return GUSI_error(ENOENT);
-
- return File_error(TFileSpec::ChDir(dir));
- }
-
- int mkdir(const char * path)
- {
- OSErr err;
- long nuDir;
- TFileSpec dir(path, true);
-
- if (dir.Error())
- return File_error(dir.Error());
-
- if (err = DirCreate(dir.vRefNum, dir.parID, dir.name, &nuDir))
- return File_error(err);
-
- return 0;
- }
-
- int rmdir(const char * path)
- {
- OSErr err;
- TFileSpec dir(path);
- CInfoPBRec info;
-
- if (err = dir.Error())
- return File_error(err);
- else if (err = dir.CatInfo(info))
- return File_error(err);
- else if (IsFile(info))
- return GUSI_error(ENOTDIR);
-
- if (err = HDelete(dir.vRefNum, dir.parID, dir.name))
- switch (err) {
- default:
- return File_error(err);
- case fBsyErr: {
- if (info.dirInfo.ioDrNmFls)
- return GUSI_error(ENOTEMPTY);
- else
- return GUSI_error(EBUSY);
- }
- }
-
- return 0;
- }
-
- char * getcwd(char * buf, size_t size)
- {
- OSErr err;
- TFileSpec cwd;
- char * res;
-
- if (err = cwd.Default()) {
- File_error(err);
-
- return nil;
- }
-
- res = cwd.FullPath();
-
- if (size < strlen(res)+1)
- return (char *) GUSI_error_nil(size > 0 ? ERANGE : EINVAL);
- if (!buf && !(buf = (char *) malloc(size)))
- return (char *) GUSI_error_nil(ENOMEM);
-
- strcpy(buf, res);
-
- return buf;
- }